perm filename MIXBUG[MIX,SYS] blob sn#020793 filedate 1972-02-29 generic text, type T, neo UTF8
COMMENT ⊗   VALID 00026 PAGES 
RECORD PAGE   DESCRIPTION
 00001 00001
 00005 00002	BEGIN	MIXBUG
 00009 00003	comment		INCHAR is a subroutine to read one char from the TTY and
 00010 00004	comment		SCAN is a subroutine to return one input token.  the token
 00013 00005	opdef	scan	[pushj p, .]
 00017 00006	comment		EXPR is a subroutine to read in and evaluate an expression.
 00023 00007	comment		WVAL is a subroutine to read in and evaluate a w-value.
 00026 00008	comment		FPOINT is a table of byte pointers for depositing things
 00027 00009	comment		INST is a subroutine to read an instruction.
 00031 00010	comment		ADDR is a subroutine to read an expression and see whether
 00033 00011	comment		GETSYM is a subroutine to find a symbolic expression for
 00036 00012	comment		these are a couple of subroutines to do some outputting:
 00038 00013	comment		MIXBUG is the starting address of the command interpreter.
 00040 00014	comment		EXAMIN is what looks at core locations and displays what it sees.
 00042 00015	esi:	addr				 get the address
 00050 00016	eb:	addr				 get address
 00052 00017	es:	addr				 get address
 00054 00018	en:	addr				 get address
 00055 00019	comment		DPOSIT is where we make deposits.
 00056 00020	di:	addrc				 get address followed by ←
 00057 00021	comment		BREAK and UBREAK are the places which handle
 00060 00022	comment		JUMPER is (would you believe) what does the jumping
 00061 00023	comment		XXXX is where we go to execute a particular instruction
 00062 00024	comment		EQUAL is used to show things in different styles
 00063 00025	comment		LF is where we display the next location
 00064 00026	BEND	MIXBUG
 00065 ENDMK
⊗;
BEGIN	MIXBUG

COMMENT	⊗	MIXBUG is the dynamic debugger that goes with MIX.  It is essentially
		a few more buttons.  Each of these buttons has <alt-mode> as
		the first character of its name.  The buttons are as follows:
			$B address	This sets a breakpoint at address.
			$U address	This removes the breakpoint at address
			$U		This removes all breakpoints
			$E address	This examines and dipslays the contents of address
					in symbolic instruction mode.
			$ES address	This examines the contents of address in symbolic decimal mode.
			$EB address	This examines the contents of address in byte mode.
			$EA address	This examines the contents of address in ALF mode
			$ED address	This examines the contents of address in decimal mode
			$EN address	This examines the contents of address in numeric-instruction mode.
			$=S address	This evaluates the address and types it (the address itself) in symbolic form.
			$=D address	This evaluates the address and types it in decimal form.
			$DW address← w-value		This deposits this w-value in this address
			$DI address← instruction	This deposits this instruction in this address.
			$J address	This begins execution at this address
			$X instruction	This causes this instruction to be executed.
			$<line-feed>	This causes *+1 to be displayed in the same mode as *

			Note:	all addresses, instructions, w-values may be
				symbolic, using the symbols of the most recently
				loaded .MLD file.  The special character *
				when not used as a multiply operator, means
				the address of the currently open location,
				if there is one, and the value of the P.C.
				if there is no currently open location.

	⊗


tac1←1
tac2←2
tac3←3
tac4←4
tac5←5
tac6←6
tac7←7
value←10
v1←11
scant←12
scnval←13
char←14
spec←←15
spec2←←16

↑acsave: block	17		; for saving the ac's
numsym:	0			; 0 if still possibly a number
seqnam:	0			; will hold the sequence name at various times
	0
origin:	-1			; will hold the value of *

comment	⊗	INCHAR is a subroutine to read one char from the TTY and
		convert it to sixbit.  the char is returned in the acc. CHAR.
		if a <c-r> is read, the following <l-f> is also read and
		returned as octal 100.
	⊗

opdef	inchar	[pushj p, .]
inchr0:	inchwl	char			; read a char
	jumpe	char, .-1		; ignore <null>
	cain	char, 11		; convert <tab>
	movei	char, " "		; to <space>
	cain	char, 15		; ignore <c-r>
	jrst	inchr0
	cain	char, 12		; convert <l-f>
	jrst	[movei	char, 100	; to octal 100
		popj	p,]		; and return
	trze	char, 100		; convert other chars to sixbit
	troa	char, 40
	trz	char, 40
	popj	p,			; return
comment	⊗	SCAN is a subroutine to return one input token.  the token
		is returned in SCANT, its associated value (if it has one)
		is returned in SCNVAL, and the first char of the next token
		is in CHAR.
		the permissable tokens are given below:
	⊗

LINE←0		; end of line
COMMA←1		; comma
LPAREN←2	; left-parenthesis
RPAREN←3	; right-parenthesis
SYM←4		; identifier or number (associated value is the MIX word for the right thing)
PLUS←5		; plus
MINUS←6		; minus
STAR←7		; asterisk (associated value is value of ORIGIN)
SLASH←10	; slash
DOWNAR←11	; double slash
COLON←12	; colon
WHAT←13		; identifier not found in symbol table
LEFTAR←14	; left arrow
SPACE←15	; space or other delimiter

comment	⊗	CHRTAB gives information about the various input chars:
		  CHRTAB+i=	0    if it is an illegal character
				k    if k is the token number for it and it isn't special
			 bits ∨ k    if k is the sixbit for the token and bits are special bits:
					bit 0 → a letter or a digit
					bit 1 → a letter
					bit 2 → a LINE or a SLASH
	⊗

ULIST1
CHRTAB:	for i ← 0,100
{ULIST2
 	j←←0
	ife i-100,	{j←← 1b2 ∨ line}
	ife i-' ',	{j←← space}
	ife i-',',	{j←← comma}
	ife i-'(',	{j←← lparen}
	ife i-')',	{j←← rparen}
	ife i-'+',	{j←← plus}
	ife i-'-',	{j←← minus}
	ife i-'*',	{j←← star}
	ife i-':',	{j←← colon}
	ife i-'←',	{j←← leftar}
	ife i-'/',	{j←← 1b2 ∨ slash}
	ifge i-'A',	{ifle i-'Z',	{j←← 3b1 ∨ i-20}}
	ifge i-'0',	{ifle i-'9',	{j←← 1b0 ∨ i-20}}
	j
}
LIST
opdef	scan	[pushj p, .]
scan00:	jumpn	char, .+3		; wait for non-blank character
	inchar
	jrst	.-2
	move	scnval, origin		; default value of scnval is ORIGIN
	skipn	scant, chrtab(char)	; check table
	jrst	bugerr			; illegal character
	tlnn	scant, 700000		; are any of the special bits on
	jrst	[inchar			; no → put next char in CHAR
		popj	p,]		; and return
	tlze	scant, 100000		; is it LINE or SLASH?
	jrst	[caie	scant, slash	; yes, is it slash?
		popj	p,		; no → it's line, so return
		inchar			; get next char
		caie	char, '/'	; is next char a slash?
		popj	p,		; no → return
		inchar			; yes → get next char
		movei	scant, downar	; and compress two slashes into downar
		popj	p,]		; and finally, return
	move	tac1, [point 6, seqnam]	; pointer to sequence name
	setzm	seqnam			; set sequence name to blanks
	setzm	seqnam+1
	movei	tac2, =12		; maximum of 12 chars
	setzb	scnval, numsym		; scnval starts as zero, numsym shows number
scan1:	tlze	scant, 200000		; is it a letter
	setom	numsym			; yes → we don't have a number
	tlz	scant, 400000		; turn off letter-digit bit
	sosl	tac2			; one more char in seqnam
	idpb	char, tac1		; so put it there
	imuli	scnval, =10		; no fix up scnval if number
	add	scnval, scant
	inchar				; get next char
	skipn	scant, chrtab(char)	; and look at table
	jrst	bugerr			; illegal character
	jumpl	scant, scan1		; if it's a digit or letter, keep the sequence going
	movei	scant, sym		; not a digit or letter, so we have whole sequence
	skipn	numsym			; was it a number?
	popj	p,			; yes → return with right token and value
	ldb	tac1, [point 8, seqnam, 7]	; hash into symbol table
	ldb	tac2, [point 8, seqnam, 15]	; by taking first two groups of 8 bits
	xor	tac1, tac2		; and XORing them
	addi	tac1, symtab		; this gives us the actual pointer
	skipa				; for the first time through
scan2:	hrrz	tac1, (tac1)		; get base address of next entry
	jumpe	tac1,	[movei	scant, what	; zero → this symbol is not in the table
			popj	p, ]		; return with bad news
	move	tac2, seqnam		; see if this entry is it
	came	tac2, (tac1) 1		; do first six chars match?
	jrst	scan2			; no → try next entry
	move	tac2, seqnam+1		; now try next six chars
	came	tac2, (tac1) 2		; do they match?
	jrst	scan2			; no → try next entry
	move	scnval, (tac1) 3	; yes → this is it so get associated MIX word
scan3:	movei	scant, sym		; it's a symbol
	popj	p,			; return
comment	⊗	EXPR is a subroutine to read in and evaluate an expression.
		it assumes that the first char of the first token is in CHAR.
		it skips on return if a valid expression was found--VALUE
		contains the MIX word generated by the expression.
		it doesn't skip if a valid expression was not found.
		in either case, the next token is in SCANT.
	⊗


opdef	expr	[pushj p, .]
expr00:	setzb	value, spec		; we initialize value to zero
	scan				; get first token
	caie	scant, sym		; if it is a symbol
	cain	scant, what		; or a what
	jrst	expreg			; see if it is a register
expr01:	caie	scant, sym		; if it is SYM
	cain	scant, star		; or *
	jrst	[move	value, scnval	; we start off
		jrst	expr2]
	caie	scant, plus		; if it is +
	cain	scant, minus		; of -
	jrst	expr1			; yes → we have a unary-operator
	aos	(p)			; otherwise it is a valid exprssion (empty)!!
	popj	p,			; so skip on return

expr1:	move	tac3, scant		; save operator
	scan				; get next token
	cain	scant, sym		; is it a symbol
	jrst	.+3			; yes → we're OK
	caie	scant, star		; or a *
	popj	p,			; no → error
	cain	tac3, minus		; was operator a minus sign?
	tlc	scnval, 400000		; yes → complement sign bit of MIX word
	move	value, scnval		; value is now what we want it to be

expr2:	scan				; get next token
	cail	scant, plus		; is it a binary-operator
	caile	scant, colon
	jrst	[aos	(p)		; no → we have found our expression
		popj	p, ]		; so skip on return
	move	tac3, scant		; remember what the operator is

expr3:	scan				; get next token
	cain	scant, sym		; is it a symbol
	jrst	.+3			; yes → we're OK
	caie	scant, star		; or *
	popj	p,			; no → error return
	move	tac4, value		; save original value
	tlze	value, 400000		; convert value to two's complement
	movns	value
	tlze	scnval, 400000		; convert scnval to two's complement
	movns	scnval
	xct	binop-plus(tac3)	; do whatever the operation calls for
	jumpg	value, expr2		; value>0 → it's already in MIX format
	jumpe	value,	[tlne	tac4, 400000	; value=0 → must check sign of first operand
			tlo	value, 400000	; first operand < 0 → new value should be also
			jrst	expr2]	; now we have MIX format
	movns	value			; value<0 → take negative
	tlo	value, 400000		; and turn on sign bit
	jrst	expr2			; and go back for next operator

binop:	add	value, scnval		; PLUS → we add the operands
	sub	value, scnval		; MINUS → we subtract the operands
	imul	value, scnval		; STAR → we multiply the operands
	idiv	value, scnval		; SLASH → we divide the operands
	pushj	p,	[setz	value+1	; DOWNAR → special divide
			ashc	value, -5
			div	value, scnval
			popj	p,]
	pushj	p,	[imuli	value, =8	; COLON → usually for fields
			add	value, scnval
			popj	p,]


expreg:	move	tac2, seqnam		; see if it is a register
	movei	tac1, reglst
	camn	tac2, (tac1)		; is it this one?
	jrst	[move	value, regnum-reglst(tac1)	; yes ← get address relative to mc0000
		setom	spec		; so we remember that it is a register
		scan			; next token must be in scant
		popj	p,]		; error return
	caige	tac1, regnum-1		; was that the last register to consider
	aoja	tac1, .-3		; no
	jrst	expr01			; yes → it wasn't a register

reglst:	sixbit	/ra/
	sixbit	/r1/
	sixbit	/r2/
	sixbit	/r3/
	sixbit	/r4/
	sixbit	/r5/
	sixbit	/r6/
	sixbit	/rx/
	sixbit	/rj/
regnum:	acsave-mc0000+ra	; give addresses in acsave relative to mc0000
	acsave-mc0000+r1
	acsave-mc0000+r2
	acsave-mc0000+r3
	acsave-mc0000+r4
	acsave-mc0000+r5
	acsave-mc0000+r6
	acsave-mc0000+rx
	acsave-mc0000+rj
comment	⊗	WVAL is a subroutine to read in and evaluate a w-value.
		it assumes that the first char of the first token is in CHAR.
		it skips on return if a valid w-value was found--VALUE
		contains the MIX word generated by the w-value.
		it doesn't skip if a valid w-value was not found.
		in either case, the next token is in SCANT.
	⊗

opdef	wval	[pushj p, .]
wval00:	setz	tac7,			; tac7 will hold w-value while it is being generated
wval1:	movei	tac6, 5			; tac6 will hold the f-part
	expr				; get an expression
	jrst	[aos	(p)		; couldn't → we're all done with w-value
		move	value, tac7	; put proper thing into value
		popj	p,]
	move	tac5, value		; save value of expression
	cain	scant, lparen		; is it a left-paren?
	jrst	wval3			; yes → go get f-part

wval2:	caile	tac6, 5			; does f-part include sign bit?
	jrst	.+4			; no
	skipge	tac5			; yes → test sign of operand
	tloa	tac7, 400000		; and use it
	tlz	tac7, 400000
	dpb	tac5, fpoint(tac6)	; now get other bytes
	cain	scant, comma		; comma?
	jrst	wval1			; yes → back for next part
	aos	(p)			; neither → we're all done
	move	value, tac7		; put proper thing into value
	popj	p,			; so skip on return

wval3:	expr				; get expression for f-part
	popj	p,			; couldn't → error in w-value
	move	tac6, value		; need to remember value of f-part
	caie	scant, rparen		; is it right-paren?
	popj	p,			; no → error in w-value
	skipl	tac6			; is it a valid f-part?
	caile	tac6, 55		; first test: is it in the right range?
	popj	p,			; no → error
	skipn	fpoint(tac6)		; is table entry zero?
	popj	p,			; yes → error
	scan				; get next token after )
	jrst	wval2			; scan again
comment	⊗	FPOINT is a table of byte pointers for depositing things
		into tac7.  if an entry is zero, then it is not a valid f-part.
		the sign byte is not included.
	⊗

fpoint:	44b5
	for y←1,5
	{point	y*6, tac7, y*6+5
	}
	repeat	2,	{0}
	for x←1,5
	{for y←0,5
	 {ifge y-x, then {point (y-x+1)*6, tac7, y*6+5
			 }
	  ifl y-x, then	 {0
			 }
	 }
	repeat	2,	{0}
	}
comment	⊗	INST is a subroutine to read an instruction.
		the MIX word which is the instruction is returned in
		VALUE.  control is transferred to bugerr if a valid
		instruction is not found.
	⊗

opdef	inst	[pushj p, .]
inst00:	scan				; get the first token
	cain	scant, sym		; is it a symbol?
	jrst	.+3			; yes → it's OK
	caie	scant, what		; or an undefined symbol?
	jrst	bugerr			; no → error
	skipe	seqnam+1		; second part of sequence name should be blanks
	jrst	bugerr			; but it's not

	movei	tac4, oplist		; no we will find op-code by a binary search
	movei	tac5, lastop		; tac4 and tac5 contain the lower and upper bounds
inst1:	move	tac1, tac5		; get index
	add	tac1, tac4
	lsh	tac1, -1		; divide by two to get average
	move	tac2, (1)		; get OP for comparison
	sub	tac2, seqnam
	jumpg	tac2, lower		; it is lower on the list
	jumpl	tac2, upper		; it is higher on the list
	skipge	tac7, gotop-oplist (tac1)	; is it a pseudo op?
	jrst	bugerr			; yes → error
	jrst	inst2			; no → success!

lower:	movni	tac5, 1			; reset upper limit
	addb	tac5, tac1		;	to index-1
	caml	tac5, tac4		; lower>upper → error
	jrst	inst1
	jrst	bugerr

upper:	movei	tac4, 1			; reset lower limit
	addb	tac4, tac1		;	to index+1
	caml	tac5, tac4		; lower>upper → error
	jrst	inst1
	jrst	bugerr

inst2:	expr				; get expression for address
	jrst	bugerr			; error
	trz	value, 770000		; get rid of bad bits
	hrl	tac7, value		; put address into assembling MIX word
	skipge	value			; was sign bit on?
	tlo	tac7, 400000		; yes → turn it on here, too
	caie	scant, comma		; is next token a comma?
	jrst	inst3			; no → then we don't have an index field
	expr				; get expression for the index field
	jrst	bugerr			; error
	dpb	value, [point 6, tac7, 23]	; put index field into MIX rd

inst3:	caie	scant, lparen		; is next token a left-parenthesis
	jrst	inst4			; no → then we don't have a field-field
	expr				; expression for field
	jrst	bugerr			; error
	caie	scant, rparen		; next token should be right-paren
	jrst	bugerr			; it ain't
	dpb	value, [point 6, tac7, 29]	; put field into MIX word
	scan				; must get next token after )

inst4:	jumpn	scant, bugerr		; final token should be LINE
	move	value, tac7		; this is the assembled instruction
	popj	p,			; so return
comment	⊗	ADDR is a subroutine to read an expression and see whether
		it is a valid address.
		it also checks to see that this is the last token in the line.
	⊗

opdef	addr	[pushj p, .]
addr0:	inchar				; input a char to start the expr
	expr				; get the expression
	jumpe	spec, bugerr		; no expression → error
	jumpn	scant, bugerr		; next expression should be LINE
	skipe	spec			; did we get a register name?
	popj	p,			; yes → return right away
	jumpl	value, bugerr		; out of range → error
	caile	value, =3999
	jrst	bugerr
	movem	value, origin		; save address in ORIGIN
	popj	p,			; return


comment	⊗	ADDRC is a subroutine to read an expression and see whether
		it is a valid address.
		it also checks to see that it is followed by a left-arrow.
	⊗

opdef	addrc	[pushj p, .]
addrc0:	inchar				; input a char to start the expr
	expr				; get the expression
	jumpe	spec, bugerr		; error
	caie	scant, leftar		; is next token a leftar?
	jrst	bugerr			; no → error
	skipe	spec			; did we get a register name
	popj	p,			; yes → return right away
	jumpl	value, bugerr		; out of range → error
	caile	value, =3999
	jrst	bugerr
	movem	value, origin		; save value of *
	popj	p,			; return
comment	⊗	GETSYM is a subroutine to find a symbolic expression for
		a value.  only symbols with equivalent MIX words between
		0000 and 3999 are considered.  GETSYM assumes that VALUE
		contains the value to be considered.  a pointer to the
		best symbol table entry is returned in tac3 (zero if no
		symbol was found) and the offset is returned in tac4.
	⊗

opdef	getsym	[pushj p, .]
↑SYMGET:				;*RES* so I can call it from MIXDD
gets0:	setz	tac3,			; we obviously haven't found a symbol yet
	movei	tac4, =4000		; and no symbol could have a worse offset than this
	movei	tac1, linked		; to start table search
gets1:	skipn	(tac1) 1		; is there an entry?
	JRST	GETS3			;*RES* no → search is over
	skipl	tac2, (tac1) 3		; is equivalent value less than zero?
	caile	tac2, =3999		; or greater than 3999?
	jrst	gets2			; yes → not a valid symbol
	sub	tac2, value		; get difference between value and symbl's equivalent
	movns	tac2			; take VALUE-SYMBOL
	jumpl	tac2, gets2		; don't want a negative offset
	caml	tac2, tac4		; is it better than we already have?
	jrst	gets2			; no → then don't use it
	move	tac3, tac1		; yes → then we should save it
	move	tac4, tac2
gets2:	addi	tac1, 4			; now look at next entry
	jrst	gets1
GETS3:	SKIPN	TAC3			;*RES* IF NO HIT,
	MOVE	TAC4,VALUE		;*RES*   SET OFFSET TO VALUE
	POPJ	P,
comment	⊗	these are a couple of subroutines to do some outputting:
			OUTDEC - output a space followed by the decimal number in VALUE
			OUTNAM - output a space followed by the sequence name in VALUE,VALUE+1
	⊗

opdef	outdec	[pushj p, .]
↑outd1:	idivi	value, =10		; get digits from right end
	hrlm	value+1, (p)		; put them on the stack
	skipe	value			; was that the last digit?
	pushj	p, outd1		; no → go back for more
	hlrz	value, (p)		; get digit off stack
	addi	value, 60		; convert to ascii
	outchr	value			; output it
	popj	p,			; next digit or return


opdef	outnam	[pushj p, .]
outnm0:	move	tac4, [point 6, value]	; pointer to chars is in tac4
outnm1:	ildb	tac5, tac4		; get a char
	jumpe	tac5, outnm2		; blank → end of sequence
	addi	tac5, 40		; convert to ascii
	outchr	tac5			; output the char
	came	tac4, [point 6, value+1, 35]	; was that the 12th char?
	jrst	outnm1			; no
outnm2:	popj	p,			; return
comment	⊗	MIXBUG is the starting address of the command interpreter.
	⊗

↑mixbug:
	movei	p, acsave		; save all ac's except p
	blt	p, acsave+16
	move	p, [iowd 40, pdl]	; initialize push-down-pointer
	skipge	origin			; do we already have an address there?
	jrst	[hrrz	tac1, acsave+pc	; no → then use value of p.c.
		subi	tac1, mc0000	; relative to mc0000
		movem	tac1, origin
		jrst	.+1]
	inchar				; input the first char
	cain	char, 'E'		; is it an E (sixbit)
	jrst	examin			; yes → go to examine
	cain	char, 'D'		; is it a D?
	jrst	dposit			; yes → go to dposit
	cain	char, 'B'		; is it a B?
	jrst	break			; yes
	cain	char, 'U'		; is it a U?
	jrst	ubreak			; yes
	cain	char, 'J'		; how about J?
	jrst	jumper			; yes
	cain	char, 'X'		; or X?
	jrst	xxxx			; yes
	cain	char, '='		; =?
	jrst	equal			; yes
	cain	char, 100		; line-feed?
	jrst	lf			; yes
					; none of these → error

bugerr:	outstr	[asciz /???
/]
bugout:	jumpe	scant, .+3		; wait for LINE
	scan
	jrst	.-2
	movsi	p, acsave		; restore all ac's
	blt	p, 16
	move	p, [iowd 40, pdl]	; restore push-down-pointer
	jrst	button			; and return to button mode
comment	⊗	EXAMIN is what looks at core locations and displays what it sees.
	⊗

examin:	inchar				; get char to tell what kind of examine
	setzm	mode			; mode will help use remember what mode of display we're in
	jumpe	char, esi		; blank → symbolic instruction
	aos	mode
	cain	char, 's'		; S → symbolic decimal
	jrst	es
	aos	mode
	cain	char, 'b'		; B → byte
	jrst	eb
	aos	mode
	cain	char, 'a'		; A → alf
	jrst	ea
	aos	mode
	cain	char, 'd'		; D → decimal
	jrst	ed
	aos	mode
	cain	char, 'n'		; N → numeric instruction
	jrst	en
	jrst	bugerr			; none of these → error


mode:	0
modes:	esi+1
	es+1
	eb+1
	ea+1
	ed+1
	en+1
esi:	addr				; get the address
	outchr	[" "]
	move	tac7, value		; tac7 will index to locatyon
	PUSHJ	P,DECIDF		;*RES* DECIDE WHETHER TO PRINT F
	JRST	ESI2			;GO DO IT

COMMENT ⊗  The following routine is called to decide whether the F-field of
	the instruction is to be printed.  It is called by PUSHJ P,DECIDF,
	with the relative instruction counter in register 7.  On return, reg
	10 contains the op code, reg 11 contains the field and reg 6 is a
	flag: zero if field is to be printed, non-zero otherwise.  As a nice
	side effect, the op code mnemonic is an ASCIZ string at @STROP(10) on
	exit.
	⊗
↑DECIDF:
	ldb	value, [point 6, mc0000(tac7), 35]	; get op code
	ldb	value+1, [point 6, mc0000(tac7), 29]	; and f-field
	setom	tac6			; tac6 will know whether we should output the field
	hlrz	tac2, strop(value)	;*RES* are there special names for different fields?
	jumpe	tac2, esi1		; no
	cain	value, 5		; is op special?
	jrst	[caile	value+1, 3
		setzb	value+1, tac6
		POPJ	P,]
	cain	value, 6		; or is it a shift?
	jrst	[caile value+1, =8
		setzb	value+1, tac6
		POPJ	P,]
	cain	value, =39		; or is it a jump?
	jrst	[caile	value+1, =12
		setzb	value+1, tac6
		POPJ	P,]
	caige	value, =40		; or one of these jumps?
	jrst	esi1
	caig	value, =47
	jrst	[caile	value+1, =8
		setzb	value+1, tac6
		POPJ	P,]
	caig	value, =55		; or one of the modifies?
	jrst	[caile	value+1, 4
		setzb	value+1, tac6
		POPJ	P,]

esi1:	cain	value, 0		; is it a NOP?
	jrst	[caie	value+1, 0
		setz	tac6,
		POPJ	P,]
	cain	value, 7		; is it a MOVE?
	jrst	[caie	value+1, 1
		setz	tac6,
		POPJ	P,]
	cain	value, =32		; is it STJ?
	jrst	[caie	value+1, 2
		setz	tac6,
		POPJ	P,]
	caige	value, =56		; is it one which has (0:5) as standard field?
	caig	value, =33
	jrst	[caie	value+1, 5
		setz	tac6,
		POPJ	P,]
	skipe	value+1			;*RES* otherwise, it uses (0)
	setz	tac6,
	POPJ	P,

esi2:	outstr	@strop(value)		; output the op-code
	outchr	["	"]		; followed by a tab
	hlrz	value, mc0000(tac7)	; get address part
	andi	value, 7777		; get good bits
	skipge	mc0000(tac7)		; is it negative?
	tlo	value, 400000		; turn on sign bit
	jumpge	value, esi23
	PUSHJ	P,GETNSM		;*RES* FIND NEG SYMBOL
	JRST	ESI22			;*RES* GO PRNT IT OUT

COMMENT ⊗  The following routine finds whether a negative address is in the 
	symbol table in either its negative form or absolute value.  It is
	called by PUSHJ P,GETNSM with the relative address reg 10.  On return,
	if there was a match in either case, register 3 contains the symbol
	table address.  If there was an exact match, reg 4 is non-zero.
	Reg 11 is destroyed.
	⊗

↑GETNSM:
	hrrz	value+1, value		; value+1 has absolute value
	setzb	tac3, tac4		; we will search for a match
	movei	tac1, linked		; of value or |value|
esi21:	skipn	(tac1) 1		; is there an entry?
	POPJ	P,			;*RES* no → end of table
	camn	value, (tac1) 3		; is this a match?
	jrst	[move	tac3, tac1	; yes → we will use it
		setom	tac4		; to remember it was exact
		POPJ	P,]		;*RES*
	camn	value+1, (tac1) 3	; match of absolute value?
	move	tac3, tac1		; yes → remember it
	ADDI	TAC1,4			;*RES* POINT TO NEXT ENTRY
	jrst	esi21			; and back to table

esi22:	jumpn	tac4, esi221		; -1 → exact match
	outchr	["-"]			; we will need this
	jumpn	tac3, esi221		;*RES* tac3=0 → no suitable symbol found
	HRRZ	VALUE,VALUE		;*RES* GET ABSOLUTE VALUE
	JRST	ESI24			;*RES* GO WRITE IT
esi221:	move	value, (tac3) 1		; output the symbol
	move	value+1, (tac3) 2
	outnam
	jrst	esi3			; all done with address field

esi23:	getsym				; get a matching symbol
	jumpe	tac3, esi24		; no match
	caile	tac4, =100		; maximum offset of 100
	jrst	esi24
	move	tac2, tac4		; remember offset
	move	value, (tac3) 1		; output name
	move	value+1, (tac3) 2
	outnam
	move	value, tac2		; now do the offset
	jumpe	value, esi3		; zero → don't type it
	outchr	["+"]
esi24:	outdec				; this could be any of several values

esi3:	ldb	value, [point 6, mc0000(tac7), 23]	; get index field
	jumpe	value, esi4		; zero → don't output it
	outchr	[","]			; comma first
	getsym				; get a matching symbol
	jumpn	tac4,	[outdec		; not an exact match, so don't use it
			jrst	esi4]
	move	value, (tac3) 1		; output the symbol
	move	value+1, (tac3) 2
	outnam
esi4:	jumpn	tac6, esi5		; are we supposed to output the field-field?
	outchr	["("]			; yes
	ldb	value, [point 6, mc0000(tac7), 29]	; get it
	getsym				; get a matching symbol
	jumpn	tac4,	[outdec		; not an exact match, so don't use it
			jrst	esi41]
	move	value, (tac3) 1		; output the symbol
	move	value+1, (tac3) 2
	outnam
esi41:	outchr	[")"]

esi5:	jrst	bugout
eb:	addr				; get address
	outchr	[" "]
	movei	tac1, "+"		; assume positive
	skipge	tac2, mc0000(value)	; are we right?
	movei	tac1, "-"		; no
	outchr	tac1			; output the sign
	move	tac1, [point 6, tac2, 5]	; pointer to bytes
eb1:	ildb	value, tac1		; get byte
	outchr	[" "]			; output a space
	outdec				; output the byte
	tlne	tac1, 770000		; is it the last byte?
	jrst	eb1			; no
	jrst	bugout			; yes



ea:	addr				; get address
	outchr	[" "]
	move	tac2, mc0000(value)	; must save pointer
	move	tac1, [point 6, tac2, 5]	; pointer to chars
ea1:	ildb	value, tac1		; get a char
	move	value, mixasc(value)	; convert to ascii
	outchr	value			; and output it
	tlne	tac1, 770000		; is is the last char?
	jrst	ea1			; no
	jrst	bugout			; yes
es:	addr				; get address
	outchr	[" "]
	move	value, mc0000(value)	; get value to output
es0:	getsym				; get symbolic expression for it
	jumpe	tac3, es1		; tac3=0 → couldn't find a symbol
	caile	tac4, =100		; maximum offset of 100
	jrst	es1
	move	tac1, tac4		; save offset
	move	value, (tac3) 1		; put sequence into value
	move	value+1, (tac3) 2	; and value+1
	outnam				; output the name
	move	value, tac1		; now get the offset
	jumpe	value, es2		; zero offset → don't print any
	outchr	["+"]
es1:	outdec				; either the offset or the entire value
es2:	jrst	bugout			; all done



ed:	addr				; get address
	outchr	[" "]
	move	value, mc0000(value)	; get the value to output
ed0:	movei	tac1, "+"		; assume positive
	jumpge	value, .+3		; right!
	movei	tac1, "-"		; wrong!!
	tlz	value, 400000		; turn off sign bit
	outchr	tac1			; output the sign
	outdec				; and then the value
	jrst	bugout			; all done
en:	addr				; get address
	outchr	[" "]
	movei	tac1, "+"		; assume positive
	skipge	tac2, mc0000(value)	; are we right?
	movei	tac1, "-"		; no
	outchr	tac1			; output the sign
	ldb	value, [point 12, tac2, 17]	; get address field
	outdec				; output it
	move	tac1, [point 6, tac2, 17]	; pointer to other fields
en1:	ildb	value, tac1		; get field
	outchr	[" "]
	outdec				; output it
	tlne	tac1, 770000		; last field?
	jrst	en1			; no
	jrst	bugout			; yes
comment	⊗	DPOSIT is where we make deposits.
	⊗

dposit:	inchar				; get next char
	cain	char, 'i'		; i?
	jrst	di			; deposit instruction
	cain	char, 'w'		; w?
	jrst	dw			; deposit w-value
	jrst	bugerr			; neither → error
di:	addrc				; get address followed by ←
	move	spec2, value		; save address to deposit into
	inst				; get instruction to put there
	movem	value, mc0000(spec2)	; so put it there
	jrst	bugout			; all done



dw:	addrc				; get address followed by ←
	move	spec2, value		; save address to deposit into
	wval				; get w-value to put there
	jrst	bugerr			; error
	movem	value, mc0000(spec2)	; so put it there
	jrst	bugout			; all done



comment	⊗	BREAK and UBREAK are the places which handle
		Break and Unbreak commands
	⊗

break:	addr				; get address to set breakpoint
	jumpl	spec, bugerr		; don't allow register names for breakpoints
	addi	value, mc0000		; make it an absolute address
	movei	tac1, =19		; is it already in the table
	camn	value, bptab(tac1)	; is it this entry?
	jrst	bugout			; yes → don't put it in again
	sojge	tac1, .-2		; check next entry
	movei	tac1, =19		; now look for blank place
	skipe	bptab(tac1)		; is this entry zero?
	sojge	tac1, .-1		; no → try next one
	jumpl	tac1,	[outstr	[asciz	/too many breakpoints
/]					; tac1<0 → went all the way through table
			jrst	bugout]
	movem	value, bptab(tac1)	; now put this address into the table
	jrst	bugout			; and return


ubreak:	inchar				; to check for line-feed
	cain	char, 100		; is U followed by <l-f>>
	jrst	ubr1			; yes → we delete all breakpoints
	addr				; get address to unbreak
	jumpl	spec, bugerr		; don't allow register names for unbreaks
	addi	value, mc0000		; make an absolute address
	movei	tac1, =19		; find it in table
	camn	value, bptab(tac1)	; this entry?
	jrst	[setzm	bptab(tac1)	; yes → make it zero
		jrst	bugout]		; and return
	sojge	tac1, .-2		; no → try next
	jrst	bugout			; couldn't find it → so what

ubr1:	movei	tac1, =19		; want to delete all entries
	setzm	bptab(tac1)		; so do it
	sojge	tac1, .-1
	jrst	bugout			; and return


↑bptab:	repeat	=20,	{0⎇		; this has the breakpoints
comment	⊗	JUMPER is (would you believe) what does the jumping
	⊗

jumper:	addr				; get address to jump to
	jumpl	spec, bugerr		; can't jump to a register name
	addi	value, mc0000		; make it an absolute address
	hrrm	value, acsave+pc	; put it in right half of  P.C.
	movsi	p, acsave		; now restore accumulators
	blt	p, 16
	move	p, [iowd 40, pdl]	; restore push-down-pointer
	jrst	mixmn1			; and resume operations
comment	⊗	XXXX is where we go to execute a particular instruction
	⊗

xxxx:	inchar				; to start off inst
	inst				; get the instruction
	setzm	jbusx			; in case it is JBUS *
	movem	value, acsave+instr	; to get set to go
	movsi	p, acsave		; now we must restore the accumulators
	blt	p, 16
	move	p, [iowd 40, pdl]	; restore push-down-pointer
	tlo	flags, siflag		; set single-instruction flag
	jrst	mixmn2			; and begin execution
comment	⊗	EQUAL is used to show things in different styles
	⊗

equal:	inchar				; get descriptive character
	cain	char, 'd'		; decimal mode
	jrst	eqd			; yes
	cain	char, 's'		; symbolic mode
	jrst	eqs			; yes
	jrst	bugerr			; neither → error


eqd:	addr				; get address to consider
	jumpl	spec, bugerr		; there are no equivalences for registers
	outchr	[" "]
	jrst	ed0			; now go do it

eqs:	addr				; get address to consider
	jumpl	spec, bugerr		; there are no equivalences for registers
	outchr	[" "]
	jrst	es0			; now go do it
comment	⊗	LF is where we display the next location
	⊗

lf:	aos	value, origin		; get next location
	skipl	tac1, mode		; now recall whatever mode we were in
	caile	tac1, 5			; within allowable range?
	jrst	bugerr			; no → error
	outchr	[15]			; <c-r> to match the <l-f> we already have
	outchr	[" "]
	jrst	@modes(tac1)		; now go do it
BEND	MIXBUG